package com.itheima.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.itheima.constant.RedisConstant;
import com.itheima.dao.SetmealDao;
import com.itheima.entity.PageResult;
import com.itheima.entity.QueryPageBean;
import com.itheima.pojo.Setmeal;
import com.itheima.service.SetmealService;
import com.itheima.utils.QiniuUtils;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.dubbo.config.annotation.Service;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import redis.clients.jedis.JedisPool;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service    //给dubbo管理
@Transactional   //事务支持
public class SetmealServiceImpl implements SetmealService {


    //本地注入dao
    @Autowired
    private SetmealDao setmealDao;

    //注入redis的连接池
    @Autowired
    private JedisPool jedisPool;

    //注入freemarker的值
    @Autowired
    private FreeMarkerConfigurer freeMarkerConfigurer;

    //注入模板文件的地址
    @Value("${out_put_path}")
    private String outPutpath;

    /**
     * 添加套餐管理
     *
     * @param setmeal       套餐基本信息
     * @param checkgroupIds 套餐下面所有的检查组
     */
    @Override
    public void add(Setmeal setmeal, Integer[] checkgroupIds) {
        //调用dao，将基本信息存储进去
        //没有id，需要反向获取
        setmealDao.add(setmeal);

        //获取到添加到数据库的文件的名称
        // TODO: 2020/10/14   为什么不在controller层实现呢？  要等文件真正写到数据库在放到集合里，controller执行后面可能会出错
        String imgName = setmeal.getImg();

        //进行非空判断
        if (imgName != null) {
            //放到redis的数据库集合里面
            jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_DB_RESOURCES, imgName);
        }

        //添加成功了，反向获取数据库自增的id
        Integer setmealId = setmeal.getId();   //套餐的id

        //将套餐关联的所有的检查组添加到中间表关系中
        for (Integer checkgroupId : checkgroupIds) {
            //循环调用添加方法，添加外键关系
            setmealDao.setSetmealAndCheckGroupId(setmealId, checkgroupId);
        }


        //再添加的时候需要生成静态页面（1 静态列表，就是开始的大页面   静态详情，就是里面每个详细信息）
        //直接调用方法进行生成
        generateMobileStaticHtml();

    }


    /**
     * 体检套餐的分页查询方法
     *
     * @param queryPageBean 传过来的查询页面信息
     * @return 所有的对象
     */
    @Override
    public PageResult findPage(QueryPageBean queryPageBean) {

        Integer currentPage = queryPageBean.getCurrentPage();//页数
        Integer pageSize = queryPageBean.getPageSize(); //每页条数
        String queryString = queryPageBean.getQueryString(); //查询条件

        //使用分页插件
        PageHelper.startPage(currentPage, pageSize);

        //调用模糊查询的方法
        Page<Setmeal> setmeals = setmealDao.findPage(queryString);

        //取出里面的数据
        long total = setmeals.getTotal();  //查询出来的总条数
        List<Setmeal> result = setmeals.getResult();  //查询出来的所有的数据的集合

        return new PageResult(total, result);
    }


    /**
     * 查询检查套餐的基本信息
     *
     * @param id 检查套餐的id
     * @return
     */
    @Override
    public Setmeal findById(Integer id, String img) {
        return setmealDao.findById(id);
    }

    /**
     * 通过检查套餐查出首选的检查组
     *
     * @param id 检查套餐的id
     * @return
     */
    @Override
    public List<Integer> findGroupIdsBysetmealId(Integer id) {

        return setmealDao.findGroupIdsBysetmealId(id);
    }

    /**
     * 修改套餐管理
     *
     * @param setmeal       套餐基本信息
     * @param checkgroupIds 套餐下面所有的检查组
     * @return
     */
    @Override
    public void update(Setmeal setmeal, Integer[] checkgroupIds) {
        //修改套餐基本信息、
        setmealDao.update(setmeal);

        //还需要找到redis里面的原有图片和云端的原有图片进行删除  通过现在的id取数据库里面查询
        //套餐的id
        Integer setmealId = setmeal.getId();

        //这是修改前的所有的数据
        Setmeal setmeal1 = setmealDao.findById(setmealId);

        //获取到图片名称
        String img = setmeal.getImg();

        //进行非空判断
        if (img != null) {
            //不是空的话表示原来有图片，就将redis和云端的删除掉
            jedisPool.getResource().srem(RedisConstant.SETMEAL_PIC_DB_RESOURCES, img);
            QiniuUtils.deleteFileFromQiniu(img);
        }

        //将这个方法redis里
        String imgName = setmeal.getImg();

        //有数据才添加
        if (imgName != null) {
            //放到redis的数据库集合里面
            jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_DB_RESOURCES, imgName);
        }
        //不是空在操作
        if (checkgroupIds != null && checkgroupIds.length > 0) {
            //删除外键关系
            setmealDao.deleteBySetmealId(setmealId);

            //添加外键关系
            //将套餐关联的所有的检查组添加到中间表关系中
            for (Integer checkgroupId : checkgroupIds) {
                //循环调用添加方法，添加外键关系
                setmealDao.setSetmealAndCheckGroupId(setmealId, checkgroupId);
            }
        }


        //再添加的时候需要生成静态页面（1 静态列表，就是开始的大页面   静态详情，就是里面每个详细信息）
        //直接调用方法进行生成
        generateMobileStaticHtml();


    }

    /**
     * 通过套餐id删除套餐
     *
     * @param id
     */
    @Override
    public void delete(Integer id) {

        //还需要找到redis里面的原有图片和云端的原有图片进行删除  通过现在的id取数据库里面查询
        //这是修改前的所有的数据
        Setmeal setmeal = setmealDao.findById(id);

        //获取到图片名称
        String img1 = setmeal.getImg();

        //进行非空判断
        if (img1 != null) {
            //不是空的话表示原来有图片，就将redis和云端的删除掉
            jedisPool.getResource().srem(RedisConstant.SETMEAL_PIC_DB_RESOURCES, img1);
            QiniuUtils.deleteFileFromQiniu(img1);
        }
        //删除外键关系
        setmealDao.deleteBySetmealId(id);
        //删除检查套餐
        setmealDao.delete(id);


        //再添加的时候需要生成静态页面（1 静态列表，就是开始的大页面   静态详情，就是里面每个详细信息）
        //直接调用方法进行生成
        generateMobileStaticHtml();

    }

    /**
     * 获取套餐的数据
     *
     * @return 封装所有预约数据的集合
     */
    public List<Setmeal> findAll() {
        //调用dao的接口进行查询
        return setmealDao.findAll();
    }

    /**
     * 获取套餐详细信息和他的关联信息（检查套餐，检查组，检查项）
     *
     * @param id 检查套餐的id
     * @return com.itheima.entity.Result
     */
    @Override
    public Setmeal findById1(Integer id) {
        return setmealDao.findById1(id);
    }

    /**
     * 生成静态的页面（静态页面分成种，一种是列表页面，一种是详细的信息）
     */
    public void generateMobileStaticHtml() {
        //获取到页面需要的数据，调用查询所有的方法，将所有的数据查询出来
        List<Setmeal> list = setmealDao.findAll();
        //第一种页面，列表页面
        generateMobileSetmealListHtml(list);
        //第二种页面，详情页面(一个套餐有一个详情页面)
        generateMobileSetmealDetailHtml(list);
    }

    /**
     * 列表的静态页面
     *
     * @param list 列表页面需要的数据
     */
    private void generateMobileSetmealListHtml(List<Setmeal> list) {
        //模板需要的数据是一个map集合
        Map map = new HashMap();
        //这个key需要和模板遍历的名称相同
        map.put("setmealList", list);
        //调用使用模板生成静态页面的方法
        // 使用 mobile_setmeal_detail.ftl 模板    m_setmerl.html 生成静态页面的名字 map 模板需要的数据
        generateHtml("mobile_setmeal.ftl", "m_setmeal.html", map);
    }


    /**
     * 生成详情页面的具体的方法
     *
     * @param list 详情页面需要的数据
     */
    private void generateMobileSetmealDetailHtml(List<Setmeal> list) {
        //有很多个详细信息，每个详细信息都要生成一个
        for (Setmeal setmeal : list) {
            //模板需要的是一个map结婚
            Map map = new HashMap();
            //将数据添加进map集合中  key和模板的对应上
            map.put("setmeal", setmealDao.findById1(setmeal.getId()));
            //调用模板生成静态页面的方法
            // 使用 mobile_setmeal_detail.ftl 模板 setmeal_detail_"+setmeal.getId()+".heml 生成静态页面的名字 map 模板需要的数据
            generateHtml("mobile_setmeal_detail.ftl", "setmeal_detail_" + setmeal.getId() + ".html", map);
        }
    }


    /**
     * 使用模板生成静态页面 通用的方法
     *
     * @param templateName 模板的名字
     * @param htmlPageName 生成静态页面后的名字
     * @param map          生成页面需要的数据
     */
    public void generateHtml(String templateName, String htmlPageName, Map map) {

        //获取配置  这个配置在配置文件已经配置了字符集和模板路径
        Configuration configuration = freeMarkerConfigurer.getConfiguration();
        Writer out = null;
        try {
            //通过配置获取模板
            Template template = configuration.getTemplate(templateName);
            //获取一个输出流，将数据输出到模板里面，生成静态页面
            //outPutpath输出后的文件的路径，htmlPageName生成的静态页面的名称
            out = new FileWriter(new File(outPutpath + "/" + htmlPageName));
            //将这个输出流输出到模板里面
            template.process(map, out);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关流
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 查询每种套餐预约的数量
     *
     * @return
     */
    @Override
    public List<Map<String, Object>> findSetmealCount() {

        return setmealDao.findSetmealCount();

    }


}
